extern crate itertools;
use itertools::Itertools;

//基本Range
fn test_range() {
    //Range由..标记产生，不包括最后一个数字，它生成步长为1的iterator
    for i in 1..11 {
        print!("{} ", i);
    }
    //1 2 3 4 5 6 7 8 9 10

    //迭代器中元素的数量
    println!();
    println!("{}", (0..10).count())
    //10
}

fn test_filter() {
    //Range递增不是1，而是增加一个不同的数字，使用filter实现
    //逆序排列rev()
    for i in (0..21).filter(|x| x%2==0).rev() {
        print!("{} ", i);
    }
    //20 18 16 14 12 10 8 6 4 2 0
    println!();

    //迭代器适配器map()将闭包应用于每个元素，并返回结果迭代器
    for i in (1..11).map(|x| x * x) {
        print!("{} ", i);
    }
    // output: 1 4 9 16 25 36 49 64 81 100
    println!();

    //fold()一个特殊的“累加器”类型闭包的结果给迭代器的所有元素
    let result = (1..5).fold(0, |acc, x| acc + x * x);
    println!("result = {}", result);

    //chain()方法组合多个范围
    let c = (1..4).chain(5..9);
    for i in c {
        print!("{} ", i);
    }
    println!();

    //与chain()相比，zip()不产生连续的迭代器，而是产生元组(tuple)的迭代器
    let cities = ["Toronto", "New York", "Melbourne"];
    let populations : [i64; 3] = [2_615_060, 8_550_405, ‎4_529_500];
    let matrix = cities.iter().zip(populations.iter());

    for (c, p) in matrix {
        println!("{:10}: population = {}", c, p);
    }
    // output:
    // Toronto   : population = 2615060
    // New York  : population = 8550405
    // Melbourne : population = 4529500
}

fn test_array() {
    let cities = ["Toronto", "New York", "Melbourne"];

    //数组不是一个迭代器。 我们需要使用iter()方法把它变成一个迭代器
    for city in cities.iter() {
        print!("{}, ", city);
    }
    // output: Toronto, New York, Melbourne,

    println!();
}

fn test_iter() {
    let nums = vec![1, 2, 3, 4, 5];

    //iter() 从矢量创建迭代器
    for i in nums.iter() {
        print!("{} ", i);
    }
    // output: 1 2 3 4 5

    println!();

    //句法糖: &
    for i in &nums {
        print!("{} ", i);
    }
    // output: 1 2 3 4 5

    println!();
}

fn test_productor_consumer() {
    //从迭代器创建一个向量，消费者collect迫使懒惰的迭代器实际产生值
    let v = (1..11).collect::<Vec<i32>>();
    println!("{:?}", v);

    //使用enumerate()方法，在每次迭代中返回一个包含索引和项目的元组
    let v = vec![1, 2, 3];
    for (i, n) in v.iter().enumerate() {
        println!("v[{}] = {}", i, n);
    }
    // output:
    // v[0] = 1
    // v[1] = 2
    // v[2] = 3

    //min()和max()，例如返回Option，分别包含向量元素的最小值和最大值
    let max = v.iter().max();
    let min = v.iter().min();
    println!("max = {:?}, min = {:?}", max, min);

    //sum()返回迭代器中所有值的总和。
    let grades = vec![4, 5, 6, 9, 7, 4, 8];
    let sum: i32 = grades.iter().sum();
    let gpa = sum as f32 / grades.len() as f32;
    println!("sum = {}, gpa = {:.2}", sum, gpa);
    // output: sum = 43, gpa = 6.14
}

fn test_infinity() {
    //take()方法来限制迭代器返回的项目数量
    let v = (1..).map(|x| x*x)
        .filter(|x| x%5==0)
        .take(10)
        .collect::<Vec<i32>>();
    println!("{:?}", v);
    // output: [25, 100, 225, 400, 625, 900, 1225, 1600, 2025, 2500]
}

fn test_itertools() {
    //step()方法
    for i in (0..11).step(2) {
        print!("{} ", i);
    }

    //unique()适配器消除了迭代器的重复
    let data = vec![1, 4, 3, 1, 4, 2, 5];
    let unique = data.iter().unique();

    for d in unique {
        print!("{} ", d);
    }

    //join()适配器将迭代器元素组合为单个字符串，元素之间有一个分隔符
    let creatures = vec!["banshee", "basilisk", "centaur"];
    let list = creatures.iter().join(", ");
    println!("In the enchanted forest, we found {}.", list);

    //sorted_by()适配器将自定义排序顺序应用于迭代器元素，返回排序后的向量
    let happiness_index = vec![ ("Austria", 12), ("Costa Rica", 14), ("Norway", 4),
                                ("Australia", 9), ("Netherlands", 7), ("New Zealand", 8), ("United States", 13),
                                ("Israel", 11), ("Denmark", 1), ("Finland", 5), ("Iceland", 3),
                                ("Sweden", 10), ("Canada", 6), ("Puerto Rico", 15), ("Switzerland", 2) ];

    let top_contries = happiness_index
        .into_iter()
        .sorted_by(|a, b| (&a.1).cmp(&b.1))
        .into_iter()
        .take(5);

    for (country, rating) in top_contries {
        println!("# {}: {}", rating, country);
    }

    // output:
    // # 1: Denmark
    // # 2: Switzerland
    // # 3: Iceland
    // # 4: Norway
    // # 5: Finland
}

fn test_custom_iter() {
    struct FahrToCelc {
        fahr: f32,
        step: f32,
    }

    impl FahrToCelc {
        fn new(fahr: f32, step: f32) -> FahrToCelc {
            FahrToCelc { fahr: fahr, step: step }
        }
    }

    impl Iterator for FahrToCelc {
        type Item = (f32, f32);

        fn next (&mut self) -> Option<Self::Item> {
            let curr_fahr = self.fahr;
            let curr_celc = (self.fahr - 32.0) / 1.8;
            self.fahr = self.fahr + self.step;
            Some((curr_fahr, curr_celc))
        }
    }

    // pass the starting temperature and step to the initializer function
    let ftc = FahrToCelc::new(0.0, 5.0);

    // produce the iterator table of first 5 values
    let temp_table = ftc.take(5);

    // print out the temperature table nicely
    for (f, c) in temp_table {
        println!("{:7.2} °F = {:7.2} °C", f, c);
    }
}

fn main() {
    test_range();
    test_filter();
    test_array();
    test_iter();
    test_productor_consumer();
    test_infinity();
    test_itertools();
    test_custom_iter();
}
